<template>
  <div class="app-container">
    <el-form
    class="searchForm" :inline="true" size="mini"
      ref="searchForm"
      :model="searchForm"
      label-width="90px"
    >
      <el-form-item label="角色名称">
        <el-input v-model="searchForm.name" placeholder="请输入角色名称" clearable />
      </el-form-item>
      <el-form-item>
        <el-button
          type="primary"
          size="mini"
          icon="el-icon-search"
          @click="doSearch"
          >搜索</el-button
        >
        <el-button
          type="default"
          size="mini"
          icon="el-icon-refresh"
          @click="resetSearch"
          >重置</el-button
        >
      </el-form-item>
    </el-form>
    <div class="searchs-content">
      <el-button
        v-permission="['system:role:add']"
        type="primary"
        size="mini"
        plain
        icon="el-icon-plus"
        @click="addDialog"
        >新增</el-button
      >
    </div>
    <Table
      :tableHeader="tableHeader"
      :tableData="tableData"
      :tableLoading="listLoading"
    >
      <template slot="action" slot-scope="scope" v-if="scope.row.id != 1">
        <el-button
          type="primary"
          size="mini"
          @click="addDialog(scope.row)"
          v-permission="['system:role:edit']"
          >编辑</el-button
        >
      </template>
    </Table>
    <pagination
      v-if="total > 0"
      :total="total"
      :page.sync="searchForm.pageNum"
      :limit.sync="searchForm.pageSize"
      @pagination="fetchData"
    />

    <!-- 弹框 -->
    <Dialog
      :visible="visible"
      width="70%"
      :loading="dialogBtnLoading"
      :title="dialogTitle"
      @confirmDialog="confirmDialog"
      @cancelDialog="cancelDialog"
    >
      <el-form
        ref="dialogForm"
        :model="dialogForm"
        label-width="120px"
        :rules="dialogRules" size="small"
      >
        <el-row>
          <el-col :span="6">
            <p style="text-align: center">基础信息</p>
            <el-form-item label="角色名称" prop="name">
              <el-input v-model="dialogForm.name" clearable placeholder="请输入角色名称" />
            </el-form-item>
            <el-form-item label="角色编码" prop="code">
              <el-input v-model="dialogForm.code" clearable placeholder="请输入角色编码" />
            </el-form-item>
            <el-form-item label="备注">
              <el-input type="textarea" :rows="5" v-model="dialogForm.remark" placeholder="请输入备注" />
            </el-form-item>
          </el-col>
          <el-col :span="8" :offset="1">
            <p style="text-align: center">管理平台权限</p>
            <!-- <el-input
              v-model="filterText"
              clearable
              placeholder="输入关键字进行过滤"
            ></el-input> -->
            <el-checkbox v-model="checkedChoose" @change="chooseAll"
              >全选/全不选</el-checkbox
            >
            <!-- <el-checkbox v-model="checkedExpand" @change="expandAll($event)"
              >展开/折叠</el-checkbox
            > -->
            <el-tree
              class="menu-tree"
              ref="menuTree"
              :data="treeData"
              show-checkbox
              node-key="id"
              check-strictly
              default-expand-all
              :default-checked-keys="treeMenuIds"
              :props="defaultProps"
              :filter-node-method="filterNode"
              @check="handleTree"
            >
            </el-tree>
          </el-col>
          <el-col :span="8" :offset="1">
            <p style="text-align: center">运维小程序权限</p>
            <el-checkbox v-model="checkedChoose2" @change="chooseAll2"
              >全选/全不选</el-checkbox
            >
            <el-tree
              class="menu-tree"
              ref="wxMenuTree"
              :data="wxTreeData"
              show-checkbox
              node-key="id"
              check-strictly
              default-expand-all
              :default-checked-keys="wxTreeMenuIds"
              :props="defaultProps"
              @check="handleTree2"
            >
            </el-tree>
          </el-col>
        </el-row>
      </el-form>
    </Dialog>
  </div>
</template>

<script>
import { roleManage } from "@/api/system";
import { getMenu } from "@/api/user";
import Pagination from "@/components/Pagination"; // secondary package based on el-pagination
import Table from "@/components/Table";
import Dialog from "@/components/Dialog";

import { handleConfirm } from "@/utils/messageBox";
import { removeNullUndefined } from "@/utils/index.js";

export default {
  components: { Pagination, Table, Dialog },
  data() {
    return {
      listLoading: true,
      total: 0,
      searchForm: {
        pageNum: 1,
        pageSize: 15,
        name: "",
      },

      tableHeader: [
        {
          type: "index",
          label: "序号",
          width: "60",
          fixed: true,
        },
        {
          label: "角色名称",
          prop: "name",
        },
        {
          label: "备注",
          prop: "remark",
        },
        { slot: "action", label: "操作", width: "240" },
      ],
      tableData: [],
      visible: false, //弹框标识
      dialogForm: {
        name: "",
        code: "",
        remark: "",
        menuIds: [],
      },
      dialogRules: {
        name: [{ required: true, message: "请输入角色名称", trigger: "blur" }],
        code: [{ required: true, message: "请输入角色编码", trigger: "blur" }],
      },
      dialogTitle: "",
      treeData: [],
      defaultProps: {
        children: "children",
        label: "name",
        disabled: "isInner",
      },
      filterText: "",
      dialogBtnLoading: false,
      checkedExpand: true,
      checkedChoose: false,
      checkedChoose2: false,
      // checkStrictly: false,
      wxTreeData: [],
      treeMenuIds: [],
      wxTreeMenuIds: [],
    };
  },
  watch: {
    filterText(val) {
      this.$refs.menuTree.filter(val);
    },
  },
  created() {
    this.fetchData();
    this.getRoleList();
  },
  methods: {
    fetchData(val) {
      this.searchForm.pageNum = val ? val.page : this.searchForm.pageNum;
      this.listLoading = true;
      this.tableData = [];
      this.total = 0;
      roleManage("/list", "get", { ...removeNullUndefined(this.searchForm) }, 2)
        .then((res) => {
          this.tableData = res.data;
          this.total = +res.total;
        })
        .finally(() => {
          this.listLoading = false;
        });
    },

    async getRoleList() {
      let data = await getMenu("/list");
      this.treeData = data.data.filter((item) => item.platformType == "P");
      this.wxTreeData = data.data.filter((item) => item.platformType == "A");
    },

    // 传参： treeData: 树形数据
    addKey(treeData) {
      return treeData.map((item) => ({
        ...item,
        disabled:
          item.isInner == 1 ||
          (item.children &&
            item.children.length > 0 &&
            item.children.filter((pp) => pp.isInner == 1).length ==
              item.children.length)
            ? true
            : false,
        children: item.children ? this.addKey(item.children) : [],
      }));
    },
    // 弹框取消
    cancelDialog() {
      this.visible = false;
      this.dialogForm = {
        name: "",
        code: "",
        remark: "",
        menuIds: [],
      };
      this.$nextTick(() => {
        //Dom更新完毕
        this.$refs.menuTree.setCheckedKeys([]);
        this.$refs.wxMenuTree.setCheckedKeys([]);
      });
      this.resetDialogForm("dialogForm");
      this.checkedChoose = false;
      this.checkedChoose2 = false;
    },
    // 弹框确认
    confirmDialog() {
      this.submitDialogForm("dialogForm");
    },
    // 新增
    addDialog(row) {
      this.visible = true;
      if (row.id) {
        this.dialogTitle = "编辑";
        let { id, name, code, remark } = row;
        this.dialogForm = { id, name, code, remark };
        this.getUserMenu(row);
      } else {
        this.dialogTitle = "新增";
      }
    },
    // 获取用户菜单权限
    async getUserMenu(row) {
      const menus = await roleManage(`/menu/list/${row.id}`, "post");
      let idsList = menus.data.map((item) => {
        return item.menuId;
      });
      this.$nextTick(() => {
        this.$refs.menuTree.setCheckedKeys(idsList);
        this.$refs.wxMenuTree.setCheckedKeys(idsList);
      });
    },
    submitDialogForm(formName) {
      this.$refs[formName].validate((valid) => {
        if (valid) {
          let msg = this.dialogForm.id ? "编辑" : "新增";
          handleConfirm(`确定要${msg}吗？`, "warning", "提示")
            .then((res) => {
              this.doOperate();
            })
            .catch((err) => {});
        } else {
          console.log("error submit!!");
          return false;
        }
      });
    },
    resetDialogForm(formName) {
      this.$refs[formName].resetFields();
    },
    filterNode(value, data) {
      if (!value) return true;
      return data.name.indexOf(value) != -1;
    },
    resetSearch() {
      this.searchForm = {
        pageNum: this.searchForm.pageNum,
        pageSize: this.searchForm.pageSize,
        name: "",
      };
    },
    doSearch() {
      this.searchForm.pageNum = 1;
      this.fetchData();
    },

    handleTree(currentObj, treeStatus) {
      // 用于：父子节点严格互不关联时，父节点勾选变化时通知子节点同步变化，实现单向关联。
      let selected = treeStatus.checkedKeys.indexOf(currentObj.id); // -1未选中,>=0为选中
      // 选中
      if (selected !== -1) {
        // 子节点只要被选中父节点就被选中(需要选中父节点时候调用此方法)
        this.selectedParent(currentObj);
        // 统一处理子节点为相同的勾选状态
        this.uniteChildSame(currentObj, true);
      } else {
        // 未选中 处理子节点全部未选中
        if (currentObj.children.length !== 0) {
          this.uniteChildSame(currentObj, false);
        }
      }
    },

    // 统一处理子节点为相同的勾选状态
    uniteChildSame(treeList, isSelected) {
      if (!treeList.isInner) {
        //非系统内置
        this.$refs.menuTree.setChecked(treeList.id, isSelected);
        for (let i = 0; i < treeList.children.length; i++) {
          this.uniteChildSame(treeList.children[i], isSelected);
        }
      }
    },
    // 统一处理父节点为选中
    selectedParent(currentObj) {
      let currentNode = this.$refs.menuTree.getNode(currentObj);
      if (currentNode.parent.key !== undefined) {
        this.$refs.menuTree.setChecked(currentNode.parent, true);
        this.selectedParent(currentNode.parent);
      }
    },

    handleTree2(currentObj, treeStatus) {
      // 用于：父子节点严格互不关联时，父节点勾选变化时通知子节点同步变化，实现单向关联。
      let selected = treeStatus.checkedKeys.indexOf(currentObj.id); // -1未选中,>=0为选中
      // 选中
      if (selected !== -1) {
        // 子节点只要被选中父节点就被选中(需要选中父节点时候调用此方法)
        this.selectedParent2(currentObj);
        // 统一处理子节点为相同的勾选状态
        this.uniteChildSame2(currentObj, true);
      } else {
        // 未选中 处理子节点全部未选中
        if (currentObj.children.length !== 0) {
          this.uniteChildSame2(currentObj, false);
        }
      }
    },

    // 统一处理子节点为相同的勾选状态
    uniteChildSame2(treeList, isSelected) {
      if (!treeList.isInner) {
        //非系统内置
        this.$refs.wxMenuTree.setChecked(treeList.id, isSelected);
        for (let i = 0; i < treeList.children.length; i++) {
          this.uniteChildSame2(treeList.children[i], isSelected);
        }
      }
    },
    // 统一处理父节点为选中
    selectedParent2(currentObj) {
      let currentNode = this.$refs.wxMenuTree.getNode(currentObj);
      if (currentNode.parent.key !== undefined) {
        this.$refs.wxMenuTree.setChecked(currentNode.parent, true);
        this.selectedParent2(currentNode.parent);
      }
    },

    // 全部选中
    chooseAll() {
      this.treeMenuIds = [];
      // 判断按钮的状态
      if (this.checkedChoose) {
        // 设置
        this.$refs.menuTree.setChecked(this.getNodeKeys(this.treeData), true);
        this.treeMenuIds = this.getNodeKeys(this.treeData);
      } else {
        this.$refs.menuTree.setCheckedNodes([]);
        this.treeMenuIds = [];
      }
    },
    getNodeKeys(nodes) {
      let keys = [];
      for (const node of nodes) {
        if (!node.isInner) {
          keys.push(node.id);
        }
        if (node.children) {
          keys = keys.concat(this.getNodeKeys(node.children));
        }
      }
      return keys;
    },
    chooseAll2() {
      this.wxTreeMenuIds = [];
      // 判断按钮的状态
      if (this.checkedChoose2) {
        // 设置
        this.$refs.wxMenuTree.setChecked(
          this.getNodeKeys(this.wxTreeData),
          true
        );
        this.wxTreeMenuIds = this.getNodeKeys(this.wxTreeData);
      } else {
        this.$refs.wxMenuTree.setCheckedNodes([]);
        this.wxTreeMenuIds = [];
      }
    },
    // 全部展开
    expandAll(value) {
      let treeList = this.treeData;
      for (let i = 0; i < treeList.length; i++) {
        this.$refs.menuTree.store.nodesMap[treeList[i].id].expanded = value;
      }
    },
    doOperate() {
      this.dialogBtnLoading = true;
      let url = this.dialogForm.id ? "/update" : "/insert";

      // 获取选中级/半选中
      let parentIds = this.$refs.menuTree.getHalfCheckedKeys();
      let childsIds = this.$refs.menuTree.getCheckedKeys();
      // 利用set没有重复的值这一特性, 实现数组去重。Array.form方法可以将 Set 结构转为数组。
      let treeMenuIds = Array.from(new Set(parentIds.concat(childsIds)));

      let parentIds2 = this.$refs.wxMenuTree.getHalfCheckedKeys();
      let childsIds2 = this.$refs.wxMenuTree.getCheckedKeys();
      let treeMenuIds2 = Array.from(new Set(parentIds2.concat(childsIds2)));

      this.dialogForm.menuIds = Array.from(
        new Set(treeMenuIds.concat(treeMenuIds2))
      );
      roleManage(url, "post", this.dialogForm, 1)
        .then((res) => {
          if (res.code == 200) {
            this.$message.success(res.message);
            this.visible = false;
            this.fetchData();
          }
        })
        .finally(() => {
          this.dialogBtnLoading = false;
        });
    },
  },
};
</script>
<style lang="scss" scoped>
.searchForm {
    .el-form-item {
        margin-bottom: 8px;
    }
}
.menu-tree {
  max-height: 450px;
  overflow-y: auto;
  margin: 10px 0;
}
</style>
